#include <iostream>
using namespace std;
#include <string>

//模板的综合案例

//实现一个自己的模板数组类
//大概的调用方式
//类名<type> arr(capacity); 创建一个类型元素类型type 容量为capacity的容器

template<class T>
class MyArr
{
public:
    MyArr(int capacity)
    {
        cout << "MyArr(int capacity)" <<endl;
        this->adress = new T[capacity];
        this->capacity = capacity;
        this->size = 0;
    }

    ~MyArr()
    {
        cout << "~MyArr()" <<endl;
        if(adress)
        {
            delete [] adress;
            adress = NULL;
        }
    }

    //因为自定义数组开辟在堆区 为防止浅拷贝问题 需要自己实现拷贝构造
    //拷贝构造需要const类型
    MyArr(const MyArr & arr)
    {
        cout << "MyArr(const MyArr & arr)" <<endl;
        this->capacity = arr.capacity;
        this->size = arr.size;
        this->adress = new T[arr.capacity]; 
        //将数据拷贝过来
        for(int i = 0; i < size; i++)
        {
            this->adress[i] = arr.adress[i];
        }
    }

    //防止=的浅拷贝问题 重载等号运算符 arr1 = arr2 arr1.operator=(arr2)
    //实现连等 返回class类型
    MyArr & operator=(const MyArr &arr)
    {
        if(adress)//先释放原来的空间
        {
            delete [] adress;
            adress = NULL;
        }
        this->capacity = arr.capacity;
        this->size = arr.size;
        this->adress = new T[arr.capacity];
        //将数据拷贝过来
        for(int i = 0; i < size; i++)
        {
            this->adress[i] = arr.adress[i];//adress本质是在堆区开辟的连续空间 支持这么访问
        }
        return *this;
    }

    void showArr()
    {
        cout << "adress: " << adress << "; capacity: " << capacity << "; size: " << size << endl;
    }

    //实现尾部插入和尾部删除数据
    void pushBack(T t)
    {
        if (size == capacity)
        {
            return;
        }

        adress[size] = t;
        size++;
    }

    void popBack()
    {
        if(size == 0)
        {
            return;
        }
        size--;
    }

    //实现通过下标访问对象中的元素 即 MyArr arr  arr[0] arr[1]
    //如果要实现对T的修改 返回引用 arr[0] = 100;
    T & operator[](int index)
    {
        return adress[index];
    }

    int getSize()
    {
        return size;
    }

    int getCapacity()
    {
        return capacity;
    }
private:
    T* adress;
    int capacity;//容量
    int size;//当前的大小
};

void printArr(MyArr<int> &arr)//显示指定
{
    for(int i = 0; i < arr.getSize(); i++)
    {
        cout << arr[i] << " ";
    }
    cout << endl;
}


//内置数据类型测试
void test01()
{
    MyArr<int> arr1(5);
    MyArr<int> arr2(arr1);
    arr2.showArr();
    arr1.showArr();
    MyArr<int> arr3(3);
    arr3 = arr2;
    arr3.showArr();

    arr3.pushBack(10);
    arr3.pushBack(20);
    arr3.pushBack(30);
    arr3.pushBack(40);

    printArr(arr3);
    cout << "capacity: " << arr3.getCapacity() << endl;
    cout << "size: " << arr3.getSize() << endl;


    arr3.popBack();
    cout << "capacity: " << arr3.getCapacity() << endl;
    cout << "size: " << arr3.getSize() << endl;
    printArr(arr3);

}

class Person
{
public:
    Person() {};//这里必须提供默认构造 否则在创建容器的时候 在堆区开辟空间 无法调用默认构造
    Person(string name, int age)
    {
        this->name = name;
        this->age = age;
    }

    string name;
    int age;
};

//自定义数据类型测试

void printPersonArr(MyArr<Person> &arr)
{
    for(int i = 0; i < arr.getSize(); i++)
    {
        cout << arr[i].name << ": " << arr[i].age << "years old" << endl;
    }
}
void test02()
{
    MyArr<Person> arr(5);

    Person p1("Tom1", 20);
    Person p2("Tom2", 21);
    Person p3("Tom3", 22);
    Person p4("Tom4", 23);
    Person p5("Tom5", 24);

    arr.pushBack(p1);
    arr.pushBack(p2);
    arr.pushBack(p3);
    arr.pushBack(p4);
    arr.pushBack(p5);

    printPersonArr(arr);
}

int main()
{
    //test01();
    test02();
    return 0;
}